/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */


package org.medbeans.modules.search.types;


import org.apache.regexp.RE;
import org.apache.regexp.RESyntaxException;


/**
 * Abstract text test.
 *
 * <p>There are mutually exclusive criteria: substring and re.
 * One of substring or re must be null.
 *
 * <p>Internally uses null as wildcard. It is presented as an empty string.
 *
 * @author  Petr Kuzel
 */
public abstract class TextType extends DataObjectType {

    /** Serial veriond UID. */
    static final long serialVersionUID = 3L;

    /** Holds value of subtring criterion. */
    protected String matchString;
    /** Case insensitive match string. */
    protected String ciMatchString;
    /** Case sensitive switch. */
    protected boolean caseSensitive;
    /** Whole words switch. */
    protected boolean wholeWords;

    /** Word separators. */
    private static String wordSeparators = " \t,;.:+-*/\\()[]{}<>=&|\"\'`~!?@#%^\n\r";

    /** Holds value of re criterion. */
    protected transient RE re;
    /** Reguler expresion. */
    protected String reString;


    // Match methods
    /** Indicates whether string matches. */
    protected boolean match(String text) {
        return matchString(text, 0) >= 0 && matchRE(text);
    }

    /** Indicates whether string matches regular expresion. */
    protected boolean matchRE(String line) {
        if ( re == null ) return true;
        return re.match(line);
    }

    /** Indicates whether string matches from specified index. */
    protected int matchString(String text, int fromIndex) {
        if (matchString == null) return 0;

        int index = caseSensitive ?
                    text.indexOf(matchString, fromIndex) :
                    text.toUpperCase().indexOf(ciMatchString, fromIndex);

        if (wholeWords && index >= 0) { // test "whole words only" condition
            if (index > 0 && wordSeparators.indexOf(text.charAt(index-1)) < 0)
                index = -1;
            else {
                int matchLen = matchString.length();
                if (index + matchLen < text.length()
                    && wordSeparators.indexOf(text.charAt(index+matchLen)) < 0)
                index = -1;
            }
        }

        return index;
    }


    // Properties
    /** Getter for <code>matchString</code> property. */
    public String getMatchString() {
        if(matchString == null) {
            return ""; // NOI18N
        } else {
            return matchString;
        }
    }

    /** Setter for <code>matchString</code> property. */
    public void setMatchString(String matchString) {
        if(matchString == null) {
            setValid(false);
            throw new IllegalArgumentException();
        }

        if (matchString.equals("")) // NOI18N
            matchString = null;

        String old = this.matchString;
        this.matchString = matchString;
        if (!caseSensitive && matchString != null)
            ciMatchString = matchString.toUpperCase();

        re = null;
        reString = null;
        setValid(true);
    }

    /** Getter for <code>caseSensitive</code> property. */
    public boolean getCaseSensitive() {
        return caseSensitive;
    }

    /** Setter for <code>caseSensitive</code> property. */
    public void setCaseSensitive(boolean caseSensitive) {
        boolean old = this.caseSensitive;
        this.caseSensitive = caseSensitive;
        if (!caseSensitive && matchString != null)
            ciMatchString = matchString.toUpperCase();
    }

    /** Getter for <code>wholeWords</code> property. */
    public boolean getWholeWords() {
        return wholeWords;
    }

    /** Setter for <code>caseSensitive</code> property. */
    public void setWholeWords(boolean wholeWords) {
        boolean old = this.wholeWords;
        this.wholeWords = wholeWords;
    }

    /** Getter for property <code>re</code>. */
    public String getRe() {
        if(reString == null) {
            return ""; // NOI18N
        } else {
            return reString;
        }
    }

    /** Setter for property <code>re</code>. 
     *@exception IllegalArgumentException if not valid regexp or <code>null</code> */
    public void setRe(String re) {
        setReImpl(re);
    }

    /** Helper method, sets regular expresion. */
    private void setReImpl(String exp) {
        if(exp == null) {
            throw new IllegalArgumentException();
        }

        String old = reString;

        if("".equals(exp)) { // NOI18N
            reString = null;
            exp = null;
            matchString=null;  //MUX
            return;
        }

        try {
            re = new RE(exp);
            reString = exp;
            matchString = null; //MUX

        } catch(RESyntaxException ex) {
            throw new IllegalArgumentException();
        }
    }

}
